package com.caits.lbs.framework.utils;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

import com.caits.lbs.framework.log.CommonLogFactory;

/**
 * <p>
 * HttpClientUtil
 * </p>
 * <p>
 * http通用工具类
 * </p>
 * @author 周华彬(zhouhuabin@sogou-inc.com, zhou_hua_bin@163.com)
 * @version 0.0.0
 *          <table style="border:1px solid gray;">
 *          <tr>
 *          <th width="100px">版本号</th>
 *          <th width="100px">动作</th>
 *          <th width="100px">修改人</th>
 *          <th width="100px">修改时间</th>
 *          </tr>
 *          <!-- 以 Table 方式书写修改历史 -->
 *          <tr>
 *          <td>0.0.0</td>
 *          <td>创建类</td>
 *          <td>zhouhuabin</td>
 *          <td>2014年8月15日 下午6:55:49</td>
 *          </tr>
 *          <tr>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          <td>XXX</td>
 *          </tr>
 *          </table>
 */
public class HttpUtils {
	/** TODO */
	private static Logger logger = CommonLogFactory.getLog();
	/** 变量:http连接生成器,类型:HttpClientBuilder */
	private static HttpClientBuilder httpClientBuilder;
	/**
	 * 发送post请求到指定url，并返回结果串 ，返回结果不能太大，否则造成内存溢出
	 * @param urlAddress
	 * @param param
	 * @return
	 */
	public static String sendPost(String urlAddress, String param, int connTimeOut, int readTimeOut, String charSet) {
		logger.debug(urlAddress + "?" + param);
		OutputStream raw = null;
		OutputStream buf = null;
		StringBuffer buffer = new StringBuffer();
		try {
			URL url = new URL(urlAddress);
			URLConnection uc = url.openConnection();
			uc.setConnectTimeout(connTimeOut);
			uc.setReadTimeout(readTimeOut);
			uc.setDoOutput(true);
			uc.setUseCaches(false);
			raw = uc.getOutputStream();
			buf = new BufferedOutputStream(raw);
			OutputStreamWriter out = new OutputStreamWriter(buf, StringUtils.null2default(charSet, FileUtils.CONST_DEFAULT_CHARSET));
			out.write(param);
			out.flush();
			out.close();
			// 接收返回信息
			BufferedReader read = new BufferedReader(new InputStreamReader(uc.getInputStream(), StringUtils.null2default(charSet, FileUtils.CONST_DEFAULT_CHARSET)));
			int ch;
			buffer = new StringBuffer(uc.getContentLength() > 0 ? uc.getContentLength() : FileUtils.CONST_BUFFERSIZE_10K);
			while ((ch = read.read()) != -1) {
				buffer.append((char) ch);
			}

		} catch (IOException ioex) {
			logger.error("请求远程数据异常,msg=" + ioex.getLocalizedMessage(), ioex);
			return null;
		} catch (Exception ex) {
			logger.error("请求远程数据异常,msg=" + ex.getLocalizedMessage(), ex);
			return null;
		} finally {
			if (buf != null) {
				try {
					buf.close();
				} catch (IOException e) {
					logger.warn("关闭输出流异常,msg=" + e.getLocalizedMessage());
				}
			}
		}

		return buffer.toString();
	}

	/**
	 * 发送get请求到指定url，并返回结果串 ,用GBK编码
	 * @param urlAddress
	 * @param connectiontimeout
	 * @param readtimeout
	 * @return
	 */
	public static String sendRequest(String urlAddress, int connTimeOut, int readTimeOut, String charSet) {
		logger.debug(urlAddress);
		StringBuffer buffer = new StringBuffer();
		try {
			URL url = new URL(urlAddress);
			URLConnection uc = url.openConnection();
			uc.setConnectTimeout(connTimeOut);
			uc.setReadTimeout(readTimeOut);
			// 接收返回信息
			BufferedReader read = new BufferedReader(new InputStreamReader(uc.getInputStream(), StringUtils.null2default(charSet, FileUtils.CONST_DEFAULT_CHARSET)));
			int ch;
			buffer = new StringBuffer();
			while ((ch = read.read()) != -1) {
				buffer.append((char) ch);
			}

		} catch (MalformedURLException e) {
			logger.error("连接失败" + e.getMessage(), e);
			return null;
		} catch (IOException ioex) {
			logger.error("请求远程数据异常,msg=" + ioex.getLocalizedMessage(), ioex);
			return null;
		} catch (Exception ex) {
			logger.error("请求远程数据异常,msg=" + ex.getLocalizedMessage(), ex);
			return null;
		}

		return buffer.toString();
	}

	/**
	 * FIXME
	 * @param urlAddress
	 * @param connTimeOut
	 * @param readTimeOut
	 * @param charSet
	 * @return
	 */
	public static String sendRequestByHttpClient(String urlAddress, int connTimeOut, int readTimeOut, String charSet) {
		logger.info(urlAddress);
		String result = null;
		HttpClientBuilder builder = HttpClientBuilder.create();
		RequestConfig config = RequestConfig.custom().setConnectTimeout(connTimeOut).setSocketTimeout(readTimeOut).build();
		builder.setDefaultRequestConfig(config);
		HttpClient httpclient = builder.build();
		HttpGet httpGet = new HttpGet(urlAddress);
		try {
			HttpResponse httpResp = httpclient.execute(httpGet);
			int statusCode = httpResp.getStatusLine().getStatusCode();
			if (statusCode == 200) {
				result = EntityUtils.toString(httpResp.getEntity());
			}
		} catch (Exception e) {
			logger.error("请求远程数据异常,msg=" + e.getLocalizedMessage(), e);
		} finally {
			httpGet.releaseConnection();
		}
		return result;
	}

	/**
	 * 发送get请求到指定url，并返流对象
	 * @param urlAddress
	 * @param connectiontimeout
	 * @param readtimeout
	 * @return
	 */
	public static InputStream getInputStreamByRequest(String urlAddress, int connTimeOut, int readTimeOut) {
		InputStream is = null;
		logger.info(urlAddress);
		try {
			URL url = new URL(urlAddress);
			URLConnection uc = url.openConnection();
			uc.setConnectTimeout(connTimeOut);
			uc.setReadTimeout(readTimeOut);
			// // 接收返回信息
			// BufferedReader read = new BufferedReader(new
			// InputStreamReader(uc.getInputStream(), "UTF-8"));
			is = uc.getInputStream();
		} catch (MalformedURLException e) {
			logger.error("连接失败,msg=" + e.getMessage(), e);
		} catch (IOException ioex) {
			logger.error("请求远程数据异常,msg=" + ioex.getLocalizedMessage(), ioex);
		} catch (Exception ex) {
			logger.error("请求远程数据异常,msg=" + ex.getLocalizedMessage(), ex);
		}

		return is;
	}

	/**
	 * 从输入流中获取数据
	 * @param inputStream 输入流
	 * @param charSet 解码字符集
	 * @param bufSize 读取缓冲大小，单位字节
	 * @return 解析后的字符串，按行输出
	 */
	public static String readDataFromStream(InputStream inputStream, String charSet, int bufSize) {
		StringBuilder data = new StringBuilder();
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, StringUtils.null2default(charSet, FileUtils.CONST_DEFAULT_CHARSET)), bufSize > 0 ? bufSize
					: FileUtils.CONST_BUFFERSIZE_100K);
			String line;
			while (null != (line = br.readLine()))
				data.append(line).append("\r\n");
		} catch (Exception e) {
			logger.error("http client error,msg=" + e.getLocalizedMessage());
			return null;
		} finally {
			if (inputStream != null) {
				try {
					inputStream.close();
				} catch (IOException e) {
					logger.error("readDataFromStream close inputStream error,msg=" + e.getLocalizedMessage());
				}
			}
		}
		return data.toString();
	}

	/**
	 * 获取客户端真实ip 
	 * @param request
	 * @return
	 */
	public static String getClientIpAddr(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}
	/**
	 * 发送单个http-post请求，用连接池
	 * @param builder	连接池生成器，为null时用系统默认的
	 * @param urlAddress	目标服务器地址
	 * @return HttpEntity	响应实体
	 */
	public static HttpEntity  sendPostByPoolConnection(HttpClientBuilder builder,String urlAddress,Map<String,String>paramMap){
		HttpClientBuilder tempBuilder = builder;
		if(tempBuilder==null)
		{
			if(httpClientBuilder==null){
				httpClientBuilder = buildPoolingHttpClientManager(100,50,3000,20000);
			}
			tempBuilder = httpClientBuilder;
		}
		CloseableHttpClient httpclient = tempBuilder.build();
		HttpPost httpPost = new HttpPost(urlAddress);
		try {
			List<NameValuePair> nvps = new LinkedList<NameValuePair>();  
			Set<String> keySet = paramMap.keySet();  
	        for(String key : keySet) {  
	            nvps.add(new BasicNameValuePair(key, paramMap.get(key)));  
	        }  
			httpPost.setEntity(new UrlEncodedFormEntity(nvps));  
			CloseableHttpResponse httpResp = httpclient.execute(httpPost);
			int statusCode = httpResp.getStatusLine().getStatusCode();
			if (statusCode == 200) {
				return httpResp.getEntity();
			}
		} catch (Exception e) {
			logger.error("请求远程数据异常,msg=" + e.getLocalizedMessage(), e);
		} finally {
			httpPost.releaseConnection();
		}
		return null;
	}
	/**
	 * 发送单个http-get请求，用连接池， 
	 * @param builder	连接池生成器，为null时用系统默认的
	 * @param urlAddress	目标服务器地址
	 * @return HttpEntity	响应实体
	 */
	public static HttpEntity  sendGetByPoolConnection(HttpClientBuilder builder,String urlAddress){
		HttpClientBuilder tempBuilder = builder;
		if(tempBuilder==null)
		{
			if(httpClientBuilder==null){
				httpClientBuilder = buildPoolingHttpClientManager(100,50,3000,20000);
			}
			tempBuilder = httpClientBuilder;
		}
		CloseableHttpClient httpclient = tempBuilder.build();
		HttpGet httpGet = new HttpGet(urlAddress);
		try {
			CloseableHttpResponse httpResp = httpclient.execute(httpGet);
			int statusCode = httpResp.getStatusLine().getStatusCode();
			if (statusCode == 200) {
				return httpResp.getEntity();
			}
		} catch (Exception e) {
			logger.error("请求远程数据异常,msg=" + e.getLocalizedMessage(), e);
		} finally {
			httpGet.releaseConnection();
		}
		return null;
	}
	/**
	 * 构建http连接池生成器,每个系统只能 
	 * @param maxRequest	最大并发连接数
	 * @param maxPerRoute	单路由的最大连接数
	 * @param connTimeOut	连接超时-毫秒
	 * @param readTimeOut	读取超时-毫秒
	 * @return HttpClientBuilder
	 */
	public static HttpClientBuilder buildPoolingHttpClientManager(int maxRequest,int maxPerRoute, int connTimeOut, int readTimeOut){
		PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
		cm.setMaxTotal(maxRequest);//连接池最大并发连接数
		cm.setDefaultMaxPerRoute(maxPerRoute);//单路由最大并发数
		HttpClientBuilder builder = HttpClients.custom().setConnectionManager(cm);
		RequestConfig config = RequestConfig.custom().setConnectTimeout(connTimeOut).setSocketTimeout(readTimeOut).build();
		builder.setDefaultRequestConfig(config);
		return	builder;
	}
}
